# -*- coding:utf-8 -*-
'''
    To do the auto orbit determining test
'''
from  builtins import range
from functools import reduce
import numpy as np
from aod.cnode import cNode
from aod.cmsg import *
from aod.cgraph import * 
from aod.satProp import BDT
from aod.hybridNode import *
from aod.satellite import *
from dataread import *

import logging
import time
import threading  
import sys
import simSettings as settings 
Stop = False

def mainProcess():
    '''
        Basic Approach
        1.initialize the sattellite states
        2.Read Inter-Sat measurements
        3.Create factor graph cooresponding to the satellite link condition
        4.do the above stuff iteratively.
    '''
    global Stop
    allDone  = False
    loggingfilename='./data/logs/debuglogfile2.log'
    f = open(loggingfilename,'w')
    f.close()
    logging.basicConfig(filename=loggingfilename,level=logging.INFO,format='%(filename)s:%(lineno)s : %(message)s')

    #logging.basicConfig(level=logging.DEBUG,format='%(filename)s:%(lineno)s : %(message)s')

    #NOTE if loadProgressFile and storeProgressFile are not equal, this process will not continue while restarting
    loadProgressFile = './data/progressData/defaultprogress-gen.data'
    storeProgressFile = './data/progressData/reviewedsim.data'
    satDataStoreFolder =  settings.SIMU_SIM_DATA_FOLDER+'singleProc_noStop/'
    measurementDataFolder = settings.SIMU_MEASUREMENT_FOLDER
    satnum = 24
    backwardMode  = 1
    np.random.seed(123)
    # variables should be stored
    # satRecordFileIndex
    # satCurrentTime
    # satInitState 
    # satTimeDrift : above four are of satellites currentState
    # frontIndex:list of line to be read of the measurement data file, such as H82-Sat10-01.txt
    # frontTime: indicates the corresponding time for frontIndex.

    # step 1: init
    data = dataRead(measurementDataFolder)
    data.fetchdata()

    progressData =  data.readProgressData(loadProgressFile)

    iterationNum =  settings.SIM_LENGTH
    satCurrentTime  = progressData['satCurrentTime'] # currentTime should be curresponding to the state
    frontTime    = progressData['frontTime'] 
    frontIndex   = progressData['frontIndex']
    satRecordFileIndex = progressData['satRecordFileIndex']
    # initial sat
    sats = []
    for i in range(0,satnum):
        satInitState =     progressData['satInitState'][i]
        satInitKineMean  = np.array(satInitState['mean'],dtype=float)
        satInitKineCov   = np.array(satInitState['cov'],dtype=float)
        satTimeDrift     = progressData['satTimeDrift'][i]
        satInitKineSate  = cStateWrapper(satInitKineMean,satInitKineCov)
        timeDrift        = cStateWrapper(np.array(satTimeDrift['mean']),np.array(satTimeDrift['cov'],dtype=float)) #TODO It is equivalent range, not just timeDrift
        sat              = cSat('sat'+str(i+1),satInitKineSate,timeDrift,backwardMode)
        sat.setCurTime(satCurrentTime[i])
        sat.initialRecord(satDataStoreFolder+sat.name)
        sat.setRecordProgress(satRecordFileIndex[i])
        sats.append(sat) # satnum is index +1
        logging.debug('sat '+str(i+1)+' has kine of')
        logging.debug(sats[i].kine.mean)

    startTime = time.time()
    for iterIndex in range(1,iterationNum+1):  #iter for iterationNum times
        tmpTimeFront = np.array(frontTime,dtype=float)
        mostRecentIndex = np.where(tmpTimeFront==tmpTimeFront.min())[0]
        forwardTime  = tmpTimeFront.min()  #NOTE forwardTime is link1endTime
        # forming linking pairs
        linkPairs  =  []
        for i  in range(0,len(mostRecentIndex)):
            satRecordIndex = mostRecentIndex[i]
            if frontIndex[satRecordIndex] >= len(data.data[satRecordIndex]):
                allDone  = True
                break
            dataRecord = data.data[satRecordIndex][frontIndex[satRecordIndex]]
            satEmitNum   = int(dataRecord[3])
            satRecNum    = int(dataRecord[4])
            if ([satEmitNum,satRecNum] in linkPairs) == False:
                linkPairs.append([satEmitNum,satRecNum])
        if allDone:
            print 'all the input file is computed'
            break

        # print len(linkPairs)
        logging.debug('link established is')
        logging.debug(linkPairs)
        logging.info('forwardTime is %f, (%d) %f'%(forwardTime,int(forwardTime/604800),forwardTime%604800))

        #Dosimulation()
        allsatsIndeices  =  list(range(1,satnum+1))
        # linkPairs        =  [[12,1]]
        for linkIndexPair in linkPairs:
            
            # assert that each sat establishes one link at most in the same time 
            assert(linkIndexPair[0] in allsatsIndeices)
            assert(linkIndexPair[1] in allsatsIndeices)
            allsatsIndeices.pop(allsatsIndeices.index(linkIndexPair[0]))
            allsatsIndeices.pop(allsatsIndeices.index(linkIndexPair[1]))

            emitSat = sats[linkIndexPair[0]-1]
            recSat  = sats[linkIndexPair[1]-1]
            logging.info('a link is computing(%d to %d)------------>>>>>>'%(linkIndexPair[0],linkIndexPair[1]))
            logging.debug("Reading measurement data")
            link1dataRecord = data.data[linkIndexPair[0]-1][frontIndex[linkIndexPair[0]-1]]
            link2dataRecord = data.data[linkIndexPair[0]-1][frontIndex[linkIndexPair[0]-1]+1]
            
            linkPara={}
            linkPara['link1endTime'] = forwardTime
            linkPara['link1measurement'] = link1dataRecord[5]
            linkPara['link2endTime'] = link2dataRecord[1]*604800+link2dataRecord[2]
            linkPara['link2measurement'] = link2dataRecord[5]

            logging.debug("link1:%f %f\n link2 : %f %f"%(linkPara['link1endTime'],linkPara['link1measurement'],linkPara['link2endTime'],linkPara['link2measurement']))
            logging.info('a link is to compute----------')
            # print linkPara
            emitSat.linkedProp(recSat,linkPara)
            emitSat.recordNow()
            recSat .recordNow()
            logging.info('a link is computed(%d to %d)<<<<<<<<<<--------'%(linkIndexPair[0],linkIndexPair[1]))
            # break
        for i  in range(0,len(mostRecentIndex)):
            satRecordIndex = mostRecentIndex[i]
            frontIndex[satRecordIndex] = frontIndex[satRecordIndex] + 2
            if frontIndex[satRecordIndex] < len(data.data[satRecordIndex]):
                frontTime[satRecordIndex]  = data.data[satRecordIndex][frontIndex[satRecordIndex]][1]*604800+data.data[satRecordIndex][frontIndex[satRecordIndex]][2]
            else:
                allDone  = True
                break
        
        endTime = time.time()
        print('A period is done:%d / %d (total/avg Time:%f / %f) '%(iterIndex,iterationNum,endTime-startTime,(endTime-startTime)/iterIndex))
        
        if Stop:
            print('Stop Message received')
            print('dumping data....')
            for i in range(0,satnum):
                sats[i].dumpRecords()
            print('done')
            print('Creating SnapShot')
            jsonData = {}
            satInitState =  []
            satTimeDrift  =  [] 
            satCurrentTime  = []
            satRecordFileIndex = []
            for satnum in range(0,satnum):
                sat =  sats[i]
                satCurrentTime.append(sat.curtruetime)
                satInitState .append({'mean':sat.kine.mean.tolist(),'cov':sat.kine.cov.tolist()} )
                satTimeDrift.append({'mean':sat.timeDrift.mean.tolist(),'cov':sat.timeDrift.cov.tolist()})
                satRecordFileIndex .append(sat.fileIndex)
            jsonData['satCurrentTime'] = satCurrentTime
            logging.info(satCurrentTime)
            logging.info('======================================')
            jsonData['satInitState'] = satInitState
            jsonData['satTimeDrift'] = satTimeDrift
            jsonData['frontTime'] = frontTime
            jsonData['frontIndex'] = frontIndex
            jsonData['satRecordFileIndex'] = satRecordFileIndex
            data.storeProgressData(jsonData,storeProgressFile)

            print('processData stored')
            print('bye')
            sys.exit(0)
    for i in range(0,satnum):
        sats[i].dumpRecords()

if __name__ == '__main__':
    thread_=threading.Thread(target=mainProcess)  
    thread_.start() 
    try:
        while True:
            if thread_.is_alive() == False:
                break
            time.sleep(1)
    except:
        Stop  = True